package com.yjt.javatest.service.impl;

//import com.alibaba.druid.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.yjt.javatest.dao.AnswerMapper;
import com.yjt.javatest.dao.StudentTestMapper;
import com.yjt.javatest.dao.TestMapper;
import com.yjt.javatest.entity.vo.StudentTestInfo;
import com.yjt.javatest.utils.SecurityUtil;
import org.apache.commons.lang.StringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yjt.javatest.dao.QuestionMapper;
import com.yjt.javatest.entity.Question;
import com.yjt.javatest.entity.Answer;
import com.yjt.javatest.service.StudentService;
import com.yjt.javatest.utils.APIResponse;
import com.yjt.javatest.utils.ErrorCode;
import com.yjt.javatest.entity.vo.AnswerVo;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;


/**
 * @author fengye
 * @Date: 2022-07-21-16:54
 * @Description:
 */
@Service
public class StudentServiceImpl extends ServiceImpl<AnswerMapper, Answer> implements StudentService {

    @Resource
    AnswerMapper answerMapper;
    @Resource
    QuestionMapper questionMapper;
    @Resource
    StudentTestMapper studentTestMapper;
    @Resource
    TestMapper testMapper;

    //需要加锁，不然一个人同时可以写两份试卷，快速点击的话
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public APIResponse submitAnswer(AnswerVo answerVo) {
        Answer studentAnswer = new Answer();
        try {
            studentAnswer.setUserId(SecurityUtil.getUserId());
            studentAnswer.setTestId(answerVo.getTestId());

            //禁止重复提交相同问卷
            Answer sA = answerMapper.selectOne(new LambdaQueryWrapper<Answer>()
                    .eq(Answer::getUserId, SecurityUtil.getUserId())
                    .eq(Answer::getTestId, answerVo.getTestId()));
            if (sA != null) {
                return APIResponse.error("禁止重复提交");
            }

            //获取答案列表
            JSONArray answersList = answerVo.getAnswersList();
            Integer allScore = 0;

            //批改
            for (int i = 0; i < answersList.size(); i++) {
                JSONObject json = answersList.getJSONObject(i);
                Long question_id = json.getLong("question_id");

                Question question = questionMapper.selectById(question_id);

                if (question == null) {
                    return APIResponse.error("没有该问题id，请联系开发人员");
                }

                JSONObject context = JSONObject.parseObject(question.getContent());
                //分类批改
                if (question.getType() == 1) {
                    //第一类比较字符串即可 ，第一类问题答案是字符串
                    //填空题
                    String answer = json.getString("answer");
                    if (answer.equals(context.getString("answer"))) {
                        allScore += question.getScore();
                    }
                } else if (question.getType() == 2) {
                    //第二类问题答案是数字
                    Double answer = json.getDouble("answer");
                    JSONObject js = json.getJSONObject("params");
                    String formula = context.getString("formula");
                    Map<String, Object> map = JSONObject.toJavaObject(js, Map.class);
                    Expression compiledExp = AviatorEvaluator.compile(formula, true);
                    Double result = (Double) compiledExp.execute(map);
                    //精度设置，该字段可以没有
                    String accuracy = context.getString("accuracy");
                    double acc = 1e-2;
                    if (StringUtils.isNotBlank(accuracy) && StringUtils.isNumeric(accuracy)) {
                        acc = Math.pow(0.1, Long.parseLong(accuracy));
                    }
                    if (Math.abs(result - answer) < acc) {
                        allScore += question.getScore();
                    }
                } else if (question.getType() == 3) {
                    //第三类问题答案是字符串
                    String formula = context.getString("formula");
                    JSONObject js = json.getJSONObject("params");
                    String answer1 = json.getString("answer");
                    Map<String, Object> map = JSONObject.toJavaObject(js, Map.class);
                    Expression compiledExp = AviatorEvaluator.compile(formula, true);
                    Double result = (Double) compiledExp.execute(map);
                    String answer = context.getString("answer");
                    String s = answer.replaceAll("\\$\\{formula}", result.toString());
                    if (s.equals(answer1)) {
                        allScore += question.getScore();
                    }
                } else if (question.getType() == 4) {
                    //
//                    Map const_param = JSONObject.toJavaObject(context.getJSONObject("const_param"), Map.class);
                    Map const_param = context.getObject("const_param", Map.class);
                    Map params = json.getObject("params", Map.class);
                    const_param.putAll(params);
                    JSONObject cal_param = context.getJSONObject("cal_param");

                    for (Map.Entry<String, Object> entry : cal_param.entrySet()) {
                        String cal = entry.getValue().toString();
                        Expression compiledExp = AviatorEvaluator.compile(cal, true);
                        Double result = (Double) compiledExp.execute(const_param);
                        const_param.put(entry.getKey(), result);
                    }
                    List<String> answer_list = context.getObject("answer_list", List.class);
                    Map answer = json.getObject("answer", Map.class);
                    boolean flag = true;
                    for (String s : answer_list) {
                        Double o = Double.valueOf(answer.get(s).toString());
                        Double o1 = Double.valueOf(const_param.get(s).toString());
                        if (flag && Math.abs(o - o1) < 1e-3) {
                            System.out.println("true");
                        } else {
                            flag = false;
                        }
                    }
                    if (flag) {
                        allScore += question.getScore();
                    }
                } else if (question.getType() == 5) {
                    List<List<String>> answer = context.getObject("answer", List.class);
                    List answer1 = json.getObject("answer", List.class);
                    JSONObject params = json.getJSONObject("params");
                    for (Object entry : params.values()) {
                        answer1.add(entry);
                    }
                    boolean flag = false;
                    for (int j = 0; j < answer.size(); j++) {
                        if (answer.get(j).containsAll(answer1)) {
                            flag = true;
                        }
                    }
                    if (flag) {
                        allScore += question.getScore();
                    }
                } else if (question.getType() == 6) {
                    String formula = context.getString("formula");

                    Map answer = json.getObject("answer", Map.class);
                    answer.putAll(context.getObject("const_param", Map.class));
                    Expression compiledExp = AviatorEvaluator.compile(formula, true);
                    Long result = (Long) compiledExp.execute(answer);
                    if (result == 1) {
                        allScore += question.getScore();
                    }
                }
            }
            studentTestMapper.updateScore(SecurityUtil.getUserId(), answerVo.getTestId(), allScore);
            studentTestMapper.updateUserAnswers(SecurityUtil.getUserId(), answerVo.getTestId(), JSON.toJSONString(answersList));
//            return APIResponse.success(ImmutableMap.of("score", allScore));
            return APIResponse.success("提交成功");
        } catch (Exception e) {
            e.printStackTrace();
            return APIResponse.error(ErrorCode.SERVER_ERROR.getCode(), "[Submit Answer Error] ：" + e.getMessage());
        }

    }


    @Override
    public APIResponse getTestInfo() {
        List<StudentTestInfo> infos = studentTestMapper.getStudentTestInfoByUserId(SecurityUtil.getUserId());
        return APIResponse.success(infos);
    }

}
